package com.community.demo.config;

import com.community.demo.extend.CustomUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@EnableWebSecurity(debug = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.inMemoryAuthentication()
//                .passwordEncoder(passwordEncoder())
//                .withUser("user")
//                .password(passwordEncoder().encode("123456"))
//                .roles("USER")
//                .and().withUser("admin")
//                .password(passwordEncoder().encode("654321"))
//                .roles("ADMIN");
        auth.userDetailsService(customUserDetailsService());
    }

    @Bean
    public UserDetailsService customUserDetailsService(){
        return new CustomUserDetailsService();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/sendemail","/user/verify/**","/test").permitAll()
                .antMatchers("/signup", "/registrationPage","/user/register").permitAll()
                .antMatchers("/user/test/bar").permitAll()
                .antMatchers("/user/test/only-user").hasAnyRole("USER")
                .antMatchers("/user/test/foo").hasAnyRole("USER", "ADMIN")
//                .antMatchers("/user/test/a").access("hasRole('ROLE_ADMIN')")
                .antMatchers("/user/test/a").access("@getAuthorize.a()")
                .anyRequest().authenticated();

        http.formLogin().loginPage("/login").permitAll()
                .loginProcessingUrl("/doLogin");
        http.logout().permitAll().logoutUrl("/logout").invalidateHttpSession(true);

        http.rememberMe().tokenValiditySeconds(3600);

        //不能用logout退出
//        http.httpBasic();

//        http.oauth2Login().loginPage("/login");

        http.csrf().disable();
        //控制用户并发
//        http.sessionManagement()
//                .maximumSessions(1)
//                .maxSessionsPreventsLogin(true);
//        http.headers().frameOptions().disable();

        //跨域
        http.cors();
    }

    /**
     * 静态资源开放，避免重定向
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/h2-console/**");
        web.ignoring().antMatchers("/h2-console/**");
        // 解决静态资源被拦截的问题
        web.ignoring().antMatchers("/images/**", "/css/**", "/js/**", "/favicon.ico", "/index.html", "/login.html");

        // TODO 此处忽略的URL过多，可能不太安全,建议根据需求情况适当开启
        web.ignoring().antMatchers("/**/*.js", "/lang/*.json", "/**/*.css", "/**/*.js", "/**/*.map", "/**/*.html", "/**/*.png"
                , "/**/*.ttf", "/**/*.svg", "/**/*.woff");

        // swagger start TODO
        web.ignoring().antMatchers("/doc.html");
        web.ignoring().antMatchers("/swagger-ui.html");
        web.ignoring().antMatchers("/swagger-resources/**");
        web.ignoring().antMatchers("/images/**");
        web.ignoring().antMatchers("/webjars/**");
        web.ignoring().antMatchers("/v2/api-docs");
        web.ignoring().antMatchers("/v2/api-docs-ext");
        web.ignoring().antMatchers("/configuration/ui");
        web.ignoring().antMatchers("/configuration/security");
        // swagger end TODO
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1
        corsConfiguration.addAllowedHeader("*"); // 2
        // 允许所有方法包括"GET", "POST", "DELETE", "PUT"等等
        corsConfiguration.addAllowedMethod("*");
//        corsConfiguration.setMaxAge(1800l);//30分钟
        // 设为true则Cookie可以包含在CORS请求中一起发给服务器。
        corsConfiguration.setAllowCredentials(true);
        // CORS请求时。XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段：
        // Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。
        // 如果想拿到其他字段，
        //允许clienHeaderWriterFiltert-site取得自定义得header值
        corsConfiguration.addExposedHeader(HttpHeaders.AUTHORIZATION);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }
}
